
#include "ps2_client_kb.h"
#include "config.h"
#include <Arduino.h>

void PS2_Client_KB::makeData() {
    if (!_PS2_KB_INFO.Enable) {
        return;
    }

    // 检查机打
    if (!_PS2_KB_INFO.KeyRepeat) {
        return;
    }

    u_long t = millis();
    if (t >= _PS2_KB_INFO.KeyDelayTime) {
        // 重置机打频率计时
        _PS2_KB_INFO.KeyDelayTime = t + _PS2_KB_INFO.KeyRepeatRate;

        // 机打指令进缓存
        copy_code(_PS2_KB_INFO.KeyRepeat, 1);
    }
}

/*******************************************************************************
 * Function Name  : ps2_copy_code
 * Description    : 将编码复制到缓存（循环储存）
 * Input          : index   PS/2扫描码序列号
 *                : type    0:断码  1：通码
 * Output         : None
 * Return         : None
 * 注： PS2_TX_E(UINT8) 范围是0~255，正好用来循环储存PS2_TXBuffer[256]而不用担心溢出
 *******************************************************************************/
void PS2_Client_KB::copy_code(uint8_t index, uint8_t type) {
    uint8_t c = 0;

    // 转换为PS/2扫描码
    c = PS2_SET2_MAKE[index];
    if (c == 0xE0) {

        switch (index) {
        case 47: // L GUI
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x1F;
            break;
        case 50: // R Ctrl
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x14;
            break;
        case 51: // R GUI
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x27;
            break;
        case 52: // R Alt
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x11;
            break;
        case 53: // application
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x2F;
            break;
        case 68: // print screen
            if (type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xE0;
                PS2_TXBuffer[PS2_TX_E++] = 0x12;
                PS2_TXBuffer[PS2_TX_E++] = 0xE0;
                PS2_TXBuffer[PS2_TX_E++] = 0x7C;
            } else {
                PS2_TXBuffer[PS2_TX_E++] = 0xE0;
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
                PS2_TXBuffer[PS2_TX_E++] = 0x7C;
                PS2_TXBuffer[PS2_TX_E++] = 0xE0;
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
                PS2_TXBuffer[PS2_TX_E++] = 0x12;
            }
            break;
        case 70: // pause
            if (type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xE1;
                PS2_TXBuffer[PS2_TX_E++] = 0x14;
                PS2_TXBuffer[PS2_TX_E++] = 0x77;
                PS2_TXBuffer[PS2_TX_E++] = 0xE1;
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
                PS2_TXBuffer[PS2_TX_E++] = 0x14;
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
                PS2_TXBuffer[PS2_TX_E++] = 0x77;
            }
            break;
        case 72: // insert
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x70;
            break;
        case 73: // home
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x6C;
            break;
        case 74: // page up
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x7D;
            break;
        case 75: // del
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x71;
            break;
        case 76: // end
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x69;
            break;
        case 77: // page down
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x7A;
            break;
        case 78: // up
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x75;
            break;
        case 79: // left
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x6B;
            break;
        case 80: // down
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x72;
            break;
        case 81: // right
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x74;
            break;
        case 83: // num /
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x4A;
            break;
        case 87: // num enter
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x5A;
            break;
        case 120: // power
            PS2_TXBuffer[PS2_TX_E++] = 0xE0;
            if (!type) {
                PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            }
            PS2_TXBuffer[PS2_TX_E++] = 0x37;
            break;
        }
    } else {
        if (type) {
            // 1：通码
            PS2_TXBuffer[PS2_TX_E++] = c;

        } else {
            // 0:断码
            PS2_TXBuffer[PS2_TX_E++] = 0xF0;
            PS2_TXBuffer[PS2_TX_E++] = c;
        }
    }
}

// 设备复位
void PS2_Client_KB::resetDevice() {
    // 初始化键盘
    _PS2_KB_INFO.STATUS = 1;
    _PS2_KB_INFO.LED = 0;    //
    _PS2_KB_INFO.Enable = 0; // 0: 停止扫描  1: 使能
    _PS2_KB_INFO.firstKeyRepeat = true;
    _PS2_KB_INFO.KeyRepeat = 0;                                    // 机打按键
    _PS2_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[0x14];          // 机打频率 —— 默认10.9cps
    _PS2_KB_INFO.KeyDelay = PS2_KeyDelay[0x01];                    // 机打延时 —— 默认500ms
    _PS2_KB_INFO.KeyDelayTime = 0;                                 // 机打延时计时
    memset(_PS2_KB_INFO.Keymode, 0, sizeof(_PS2_KB_INFO.Keymode)); // 按键的新状态 0：释放， 1按下

    PS2_TX_S = PS2_TX_E;             // 清空缓存——不发送
    PS2_TXBuffer[PS2_TX_E++] = 0xAA; // 复位成功
}

/*******************************************************************************
 * Function Name  : readAndExec
 * Description    : 接收和执行指令
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void PS2_Client_KB::readAndExec() {
    uint8_t s;
    uint8_t cmd;
    uint8_t para;

    static int step = 0;
    static unsigned long delay = 0;

    if (step == 0) {

        // 接收到缓存
        s = readIntoBuffer();
        if (s == 2) {
            // 读取到错误数据
            sendByte(0xFE); // 请求重发
            return;
        } else if (s == 1) {
            cmd = PS2_RXBuffer;
        } else {
            return;
        }

        // printf("cmd[x%02X]\n", cmd);

        switch (cmd) {
        case 0xED: // 设置键盘LED
        case 0xF0: // 设置或查询编码集合
        case 0xF3: // 设置键盘机打速率和延时
            // 双字节指令，第一周期只回送 0xFA
            sendByte(0xFA);

            // 读取第二字节
            while (1) {
                s = readIntoBuffer();
                if (s == 2) {
                    // 读取到错误数据
                    sendByte(0xFE); // 请求重发
                } else if (s == 1) {
                    para = PS2_RXBuffer;
                    break;
                }
            }
            // printf("para[x%02X]\n", para);
            break;
        }

        switch (cmd) {
        case 0xED: // 设置键盘LED
            _PS2_KB_INFO.LED = para;
            sendByte(0xFA); // 回复
            _pCallbacks->ps2kb_setLED(_PS2_KB_INFO.LED);
            break;
        case 0xF0: // 设置或查询编码集合
            if (para) {
                sendByte(0xFA); // 回复
            } else {
                sendByte(0x02); // 回复 —— 使用第二套编码集
            }
            break;
        case 0xF2:               // 询问device id
            PS2_TX_S = PS2_TX_E; // 清空缓存
            PS2_TXBuffer[PS2_TX_E++] = 0xFA;
            PS2_TXBuffer[PS2_TX_E++] = 0xAB;
            PS2_TXBuffer[PS2_TX_E++] = 0x83;
            break;
        case 0xF3:          // 设置键盘机打速率和延时
            sendByte(0xFA); // 回复
            // _PS2_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[para & 0x1F]; // 机打频率 —— 默认10.9cps
            // para >>= 5;
            // _PS2_KB_INFO.KeyDelay = PS2_KeyDelay[para & 0x03]; // 机打延时 —— 默认500ms

            // windows给的指令太慢
            _PS2_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[0x16]; // 机打频率 —— 默认10.9cps
            _PS2_KB_INFO.KeyDelay = PS2_KeyDelay[0x01];           // 机打延时 —— 默认500ms
            break;
        case 0xF4:          // 使能键盘
            sendByte(0xFA); // 回复
            _PS2_KB_INFO.Enable = 1;
            break;
        case 0xF5: // 禁止键盘
            _PS2_KB_INFO.Enable = 0;
            sendByte(0xFA);      // 回复
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            break;
        case 0xF6:                                                // 设置缺省
            _PS2_KB_INFO.KeyRepeatRate = PS2_KeyRepeatRate[0x14]; // 机打频率 —— 默认10.9cps
            _PS2_KB_INFO.KeyDelay = PS2_KeyDelay[0x01];           // 机打延时 —— 默认500ms
            memset(_PS2_KB_INFO.Keymode, 0, sizeof(_PS2_KB_INFO.Keymode));
            sendByte(0xFA);      // 回复
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            break;
        case 0xF7:                                                            // 设置按键的发送方法
            sendByte(0xFA);                                                   // 回复
            memset(_PS2_KB_INFO.Keymode, 0x02, sizeof(_PS2_KB_INFO.Keymode)); // 不发送断码
            PS2_TX_S = PS2_TX_E;                                              // 清空缓存——不发送
            break;
        case 0xF8:                                                            // 设置按键的发送方法
            sendByte(0xFA);                                                   // 回复
            memset(_PS2_KB_INFO.Keymode, 0x01, sizeof(_PS2_KB_INFO.Keymode)); // 不发送机打
            PS2_TX_S = PS2_TX_E;                                              // 清空缓存——不发送
            break;
        case 0xF9:                                                            // 设置按键的发送方法
            sendByte(0xFA);                                                   // 回复
            memset(_PS2_KB_INFO.Keymode, 0x03, sizeof(_PS2_KB_INFO.Keymode)); // 不发送断码和机打
            PS2_TX_S = PS2_TX_E;                                              // 清空缓存——不发送
            break;
        case 0xEE:          // 查响应
            sendByte(0xEE); // 回复
            break;
        // case 0xFE:      // 重新发送最后一个字节  —— 已在指令接收阶段处理
        //     break;
        case 0xFA:                                                         // 复位所有键盘的默认发送方式
            sendByte(0xFA);                                                // 回复
            memset(_PS2_KB_INFO.Keymode, 0, sizeof(_PS2_KB_INFO.Keymode)); // 按键的新状态 0：释放， 1按下
            break;
        case 0xFF:                           // 复位键盘
            sendByte(0xFA);                  // 回复成功
            PS2_TX_S = PS2_TX_E;             // 清空缓存——不发送
            _pCallbacks->ps2kb_setLED(0x07); // 点亮所有LED
            delay = millis() + 300;
            step = 1;
            break;
        default:
            sendByte(0xFA); // 回复
            break;
        }
    } else if (step == 1) {
        if (millis() >= delay) {
            resetDevice();
            _pCallbacks->ps2kb_setLED(0x00); // 熄灭所有LED
            step = 0;
        }
    }
}

void PS2_Client_KB::setKey(int key, int status) {

    if (!_PS2_KB_INFO.Enable) {
        return;
    }

    copy_code(key, status);

    if (status) {
        // 设置机打按键
        _PS2_KB_INFO.KeyRepeat = key;
        _PS2_KB_INFO.KeyDelayTime = millis() + _PS2_KB_INFO.KeyDelay; // 机打延时计时

    } else {
        _PS2_KB_INFO.KeyRepeat = 0;
    }
}

void PS2_Client_KB::setEventCallbacks(PS2_Client_KB_Callbacks *pCallbacks) {
    _pCallbacks = pCallbacks;
}